import { createStore, Commit } from "vuex";
import axios, { AxiosRequestConfig } from 'axios';
import { arrToObj, objToArr } from './helper'
export interface ResponseType<P = { [key: string]: any }> {
  code: number;
  msg: string;
  data: P;//data是不同的变化，用泛型
}

export interface UserProps {
    isLogin:boolean;//类型
    nickName?:string;
    _id?:string;
    column?: string;
    email?:string;
    avatar?: ImageProps;
    description?: string;
}

export interface ImageProps{
    _id?:string;
    url?:string;
    createdAt?:string;
    fitUrl?: string;
}

export interface ColumnProps {
    _id: string;
    title: string;
    avatar?: ImageProps;
    description: string;
  }

  export interface PostProps {
    _id?: string;
    title: string;
    excerpt?: string;
    content?: string;
    image?: ImageProps | string;
    createdAt?: string;
    column: string;
    author?: string | UserProps;
    isHTML?: boolean;
  }

  interface ListProps<P> {
    [id: string]: P;
  }

export interface GlobalErrorProps {
    status: boolean;
    message?: string;
}

export interface GlobalDataProps {
    error: GlobalErrorProps;
    token:string;
    loading:boolean;
    columns: { data: ListProps<ColumnProps>; currentPage:number;total:number };
    posts: { data: ListProps<PostProps>; loadedColumns: string[] };
    user:UserProps;
}

const asyncAndCommit = async(url: string, mutationName: string, 
    commit: Commit, config: AxiosRequestConfig = { method: 'get' },extraData?:any) => {
    const { data } = await axios(url, config)
    if(extraData){
        commit(mutationName,{data,extraData})
    } else{
        commit(mutationName, data)
    }
    
    return data
  }
//<> GlobalDataProps传入泛型里面去
const store = createStore<GlobalDataProps>({
    state:{
        error: { status: false },
        token:localStorage.getItem('token') || '',
        loading:false,
        // columns: testData,//引入后赋值
        columns: { data: {}, currentPage:0, total:0 },
        // posts: testPosts,
        posts: { data: {}, loadedColumns: [] },
        user:{ isLogin: false },
    },
    mutations:{
        // login(state){
        //     state.user =  {...state.user, isLogin:true, name:'viking'}
        // },
        createPost(state,newPost){
            // state.posts.push(newPost)
            state.posts.data[newPost._id] = newPost
        },
        fetchColumns(state,rawData){
            const { data } = state.columns
            const { list, count, currentPage } = rawData.data
            state.columns = {
                data: { ...data, ...arrToObj(list)},
                total:count,
                currentPage:currentPage * 1
            }
        },
        fetchColumn(state,rawData){
            state.columns.data[rawData.data._id] = rawData.data;
        },
        fetchPosts(state,{data:rawData,extraData:columnId}){
            state.posts.data = { ...state.posts.data, ...arrToObj(rawData.data.list)};
            state.posts.loadedColumns.push(columnId)
        },
        fetchPost(state, rawData) {
            // state.posts = [rawData.data]
            state.posts.data[rawData.data._id] = rawData.data;
        },
        deletePost(state,{ data }){
            // state.posts = state.posts.filter(post => post._id !== data._id)
            delete state.posts.data[data._id]
        },
        updatePost(state, { data }) {
            /* state.posts = state.posts.map(post => {
              if (post._id === data._id) {
                return data
              } else {
                return post
              }
            }) */
              state.posts.data[data._id] = data
          },
        setLoading(state,status){
            state.loading = status
        },
        setError(state, e: GlobalErrorProps) {
            state.error = e
        },
        fetchCurrentUser(state,rawData){
            state.user = { isLogin:true, ...rawData.data}
        },
        login(state,rawData){
            const { token } = rawData.data;
            localStorage.setItem('token', token)
            state.token = token;
            axios.defaults.headers.common.Authorization = `Bearer ${token}`
        },
        logout(state){
            state.token = '';
            state.user = { isLogin: false }
            localStorage.remove('token');
            delete axios.defaults.headers.common.Authorization
        }
    },
    actions:{
        fetchColumns({ state, commit }, params = {}){
            const { currentPage = 1, pageSize = 6 } = params;
            /* if(!state.columns.isLoaded){
                //这样看起来比较简单，放到函数中去
                return  asyncAndCommit('/columns','fetchColumns',commit)
            } */
           if(state.columns.currentPage < currentPage){
            return asyncAndCommit(`/columns?currentPage=${currentPage}&pageSize=${pageSize}`,'fetchColumns',commit)
           }
            //换这种写法
            /* const { data } = await axios.get('/columns')
            commit('fetchColumns',data) */
            /* axios.get('/columns').then(resp =>{
                commit("fetchColumns",resp.data)
            }) */
        },
        fetchColumn({ state, commit }, cid){
            if(!state.columns.data[cid]){
            // axios.get(`/columns/${cid}`).then(resp =>{
            //     commit('fetchColumn',resp.data)
            // })
               return asyncAndCommit(`/columns/${cid}`,'fetchColumn',commit)
            }
        },
        fetchPosts({ state, commit }, cid){
            if(!state.posts.loadedColumns.includes(cid)){
                return asyncAndCommit(`/columns/${cid}/posts`,'fetchPosts',commit,{ method:'get' },cid)
            }
        },
        fetchPost({state, commit }, id) {
            const currentPost = state.posts.data[id]
            if(!currentPost || !currentPost.content){
                return asyncAndCommit(`/posts/${id}`, 'fetchPost', commit)
            }else{
                return Promise.resolve({ data:currentPost })
            }
        },
        updatePost({ commit }, { id, payload }) {
            return asyncAndCommit(`/posts/${id}`, 'updatePost', commit, {
              method: 'patch',
              data: payload
            })
          },
        fetchCurrentUser ({ commit }) {
            return asyncAndCommit('/user/current', 'fetchCurrentUser', commit)
          },
        login({ commit },payload){
            // return postAndCommit('/user/login','login',commit,payload)
            return asyncAndCommit('/user/login','login',commit,payload)
        },
        createPost({ commit }, payload) {
            // return postAndCommit('/posts', 'createPost', commit, payload)
            return asyncAndCommit('/posts', 'createPost', commit, payload)
        },
        deletePost({ commit },id){
            return asyncAndCommit(`/posts/${id}`,'deletePost',commit, { method: 'delete' })
        },
        loginAndFetch({ dispatch }, loginData) {
            return dispatch('login', loginData).then(() => {
                return dispatch('fetchCurrentUser')
            })
        }
    },
    getters:{
        getColumns: (state) => {
            return objToArr(state.columns.data)
          },
        /* biggerColumnsLen(state){
            return state.columns.filter(c => c.id >2).length
        }, */
        getColumnById:(state) =>(id:string) =>{
            // return state.columns.find(c => c._id == id)
            return state.columns.data[id]
        },
        getPostsByCid:(state) => (cid:string) =>{
            // return state.posts.filter(post => post.column == cid)
            return objToArr(state.posts.data).filter(post => post.column == cid)
        },
        getCurrentPost: (state) => (id: string) => {
            // return state.posts.find(post => post._id === id)
            return state.posts.data[id]
        }
    }
})

export default store